口碑扑街?Python告诉你《囧妈》到底囧在哪里?
The following article comes from CDA数据分析师 Author 坚决不出门的C君
2020 年的春节档之前被誉为神仙打架,各显神通,可以说是史上最强的春节档,不料一场疫情,就换了另一个局面。为配合疫情的防控,春节档电影全部撤档。
本以为就这样没下文了,结果徐峥打出一张牌:线上免费看《囧妈》,作为发行方的欢喜传媒股票当天也应声上涨 42%。今天我们就来聊聊另类春节档的唯一一部电影《囧妈》。
《囧妈》绕过院线,全网免费看
为了最终抵达莫斯科,他不得不和母亲共同克服难关,并面对家庭生活中一直所逃避的问题。
敢做第一个吃螃蟹的人
记得当时看完《人在囧途》,就说下次徐峥再拍囧系列一定要去电影院支持,这种口碑效应在电影里面特别明显。可能正是这样的艺高,所以才胆大。
观众看完之后是什么反应
获取数据
数据预处理
数据可视化
获取数据
评论用户 ID
评论用户主页
评论内容
评分星级
评论日期
用户所在城市
代码实现:
# 导入所需包
import requests
from bs4 import BeautifulSoup
import numpy as np
import pandas as pd
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
# 定义登录函数
def login_douban():
'''功能:自动登录豆瓣网站'''
global browser # 设置为全局变量
browser = webdriver.Chrome()
# 进入登录页面
login_url = 'https://accounts.douban.com/passport/login?source=movie'
browser.get(login_url)
# 点击密码登录
browser.find_element_by_class_name('account-tab-account').click()
# 输入账号和密码
username = browser.find_element_by_id('username')
username.send_keys('18511302788')
password = browser.find_element_by_id('password')
password.send_keys('12349148feng')
# 点击登录
browser.find_element_by_class_name('btn-account').click()
# 定义函数获取单页数据
def get_one_page(url):
'''功能:传入url,豆瓣电影一页的短评信息'''
# 进入短评页
browser.get(url)
# 使用bs解析网页数据
bs = BeautifulSoup(browser.page_source, 'lxml')
# 获取用户名
username = [i.find('a').text for i in bs.findAll('span', class_='comment-info')]
# 获取用户url
user_url = [i.find('a')['href'] for i in bs.findAll('span', class_='comment-info')]
# 获取推荐星级
rating = []
for i in bs.findAll('span', class_='comment-info'):
try:
one_rating = i.find('span', class_='rating')['title']
rating.append(one_rating)
except:
rating.append('力荐')
# 评论时间
time = [i.find('span', class_='comment-time')['title'] for i in bs.findAll('span', class_='comment-info')]
# 短评信息
short = [i.text for i in bs.findAll('span', class_='short')]
# 投票次数
votes = [i.text for i in bs.findAll('span', class_='votes')]
# 创建一个空的DataFrame
df_one = pd.DataFrame()
# 存储信息
df_one['用户名'] = username
df_one['用户主页'] = user_url
df_one['推荐星级'] = rating
df_one['评论时间'] = time
df_one['短评信息'] = short
df_one['投票次数'] = votes
return df_one
# 定义函数获取25页数据(目前所能获取的最大页数)
def get_25_page(movie_id):
'''功能:传入电影ID,获取豆瓣电影25页的短评信息'''
# 创建空的DataFrame
df_all = pd.DataFrame()
# 循环追加
for i in range(25):
url = "https://movie.douban.com/subject/{}/comments?start={}&limit=20&sort=new_score&status=P".format(movie_id,i*20)
print('我正在抓取第{}页'.format(i+1), end='\r')
# 调用函数
df_one = get_one_page(url)
df_all = df_all.append(df_one, ignore_index=True)
# 程序休眠一秒
time.sleep(1.5)
return df_all
if __name__ == '__main__':
# 先运行登录函数
login_douban()
# 程序休眠两秒
time.sleep(2)
# 再运行循环翻页函数
movie_id = 30306570 # 囧妈
df_all = get_25_page(movie_id)
爬取出来的数据以数据框的形式存储,结果如下所示:
数据预处理
推荐星级:转换为 1-5 分。
评论时间:转换为时间类型,提取出日期信息。
城市:有城市空缺、海外城市、乱写和 pyecharts 尚不支持的城市,需要进行处理。
短评信息:需要进行分词和提取关键词。
# 定义函数转换推荐星级字段
def transform_star(x):
if x == '力荐':
return 5
elif x == '推荐':
return 4
elif x == '还行':
return 3
elif x == '较差':
return 2
else:
return 1
# 星级转换
df_all['星级'] = df_all.推荐星级.map(lambda x:transform_star(x))
# 转换日期类型
df_all['评论时间'] = pd.to_datetime(df_all.评论时间)
# 提取日期
df_all['日期'] = df_all.评论时间.dt.date
# 定义函数-获取短评信息关键词
def get_comment_word(df):
'''功能:传入df,提取短评信息关键词'''
# 导入库
import jieba.analyse
import os
# 去停用词
stop_words = set()
# 加载停用词
cwd = os.getcwd()
stop_words_path = cwd + '\\stop_words.txt'
with open(stop_words_path, 'r', encoding='utf-8') as sw:
for line in sw.readlines():
stop_words.add(line.strip())
# 添加停用词
stop_words.add('6.3')
stop_words.add('一张')
stop_words.add('一部')
stop_words.add('徐峥')
stop_words.add('徐导')
stop_words.add('电影')
stop_words.add('电影票')
# 合并评论信息
df_comment_all = df['短评信息'].str.cat()
# 使用TF-IDF算法提取关键词
word_num = jieba.analyse.extract_tags(df_comment_all, topK=100, withWeight=True, allowPOS=())
# 做一步筛选
word_num_selected = []
# 筛选掉停用词
for i in word_num:
if i[0] not in stop_words:
word_num_selected.append(i)
else:
pass
return word_num_selected
key_words = get_comment_word(df_all)
key_words = pd.DataFrame(key_words, columns=['words','num'])
数据可视化
总体评分分布
评分时间走势图
评论用户城市分布
评论词云图
代码实现:
# 总体评分百分比
score_perc = df_all.星级.value_counts() / df_all.星级.value_counts().sum()
score_perc = np.round(score_perc*100,2)
# 导入所需包
from pyecharts import options as opts
from pyecharts.charts import Pie, Page
# 绘制柱形图
pie1 = Pie(init_opts=opts.InitOpts(width='1350px', height='750px'))
pie1.add("",
[*zip(score_perc.index, score_perc.values)],
radius=["40%","75%"])
pie1.set_global_opts(title_opts=opts.TitleOpts(title='总体评分分布'),
legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
toolbox_opts=opts.ToolboxOpts())
pie1.set_series_opts(label_opts=opts.LabelOpts(formatter="{c}%"))
pie1.render('总体评分分布.html')
代码实现:
# 时间排序
time = df_all.日期.value_counts()
time.sort_index(inplace=True)
from pyecharts.charts import Line
# 绘制时间走势图
line1 = Line(init_opts=opts.InitOpts(width='1350px', height='750px'))
line1.add_xaxis(time.index.tolist())
line1.add_yaxis('评论热度', time.values.tolist(), areastyle_opts=opts.AreaStyleOpts(opacity=0.5), label_opts=opts.LabelOpts(is_show=False))
line1.set_global_opts(title_opts=opts.TitleOpts(title="时间走势图"), toolbox_opts=opts.ToolboxOpts())
line1.render('评论时间走势图.html')
首先是用条形图,来粗略的展示前十大热门的影迷城市。
代码实现:
# 国内城市top10
city_top10 = df_all.城市处理.value_counts()[:12]
city_top10.drop('国外', inplace=True)
city_top10.drop('未知', inplace=True)
from pyecharts.charts import Bar
# 条形图
bar1 = Bar(init_opts=opts.InitOpts(width='1350px', height='750px'))
bar1.add_xaxis(city_top10.index.tolist())
bar1.add_yaxis("城市", city_top10.values.tolist())
bar1.set_global_opts(title_opts=opts.TitleOpts(title="评论者Top10城市分布"),toolbox_opts=opts.ToolboxOpts())
bar1.render('评论者Top10城市分布条形图.html')
为大家更加直观的进行展示,选取了观影城市最多的前三十个城市作为动态展示,如下图所示:
代码实现:
city_num = df_all.城市处理.value_counts()[:30]
city_num.drop('国外', inplace=True)
city_num.drop('未知', inplace=True)
c1 = Geo(init_opts=opts.InitOpts(width='1350px', height='750px'))
c1.add_schema(maptype='china')
c1.add('geo', [list(z) for z in zip(city_num.index, city_num.values.astype('str'))], type_=ChartType.EFFECT_SCATTER)
c1.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
c1.set_global_opts(visualmap_opts=opts.VisualMapOpts(),
title_opts=opts.TitleOpts(title='评论者城市分布'),
toolbox_opts=opts.ToolboxOpts())
c1.render('评论者城市分布地图.html')
代码实现:
from pyecharts.charts import WordCloud
from pyecharts.globals import SymbolType, ThemeType
word = WordCloud(init_opts=opts.InitOpts(width='1350px', height='750px'))
word.add("", [*zip(key_words.words, key_words.num)], word_size_range=[20, 200])
word.set_global_opts(title_opts=opts.TitleOpts(title="囧妈电影评论词云图"),
toolbox_opts=opts.ToolboxOpts())
word.render('囧妈电影评论词云图.html')
在热门评论里,用户阿暖说道:“ 很平庸,很无趣,既不好笑,对于原生家庭的探讨也只是隔靴搔痒而已。”
2010 年《人在囧途》,豆瓣 7.7 分。主演是徐峥,导演叶伟民。
2012 年《人在囧途之泰囧》,豆瓣 7.4 分,徐峥自导自演。
2015 年《港囧》,豆瓣 5.7 分,徐峥自导自演。
2018 年《我不是药神》,豆瓣 9.0 分,主演是徐峥,导演是文牧野。
2020 年《囧妈》,豆瓣 5.9 分,徐峥自导自演。
作者:坚决不出门的 C 君
编辑:陶家龙、孙淑娟
出处:转载自微信公众号 CDA 数据分析师(ID: cdacdacda)
精彩文章推荐:
年后跳槽到阿里,我有话想说......新来的实习生不小心删库了,吓得我虎躯一震!
爬了8W条弹幕评论,4000万人熬夜“监工”,不是无聊,是期望